<?
/**
 * VoiceOne Webservices Methods
 *  
 * @package voiceone_webservices
 * @subpackage ast_commands
 */
//******************************************************************************
//******************           PUBLIC FUNCTIONS            *********************
//******************************************************************************
// ---- Function ast_originate -------------------------------------------------
/**
* Originate a call through asterisk proxy manager. This method open a socket to the proxy
* and send in it login command, originate command and logoff command. 
* Socket settings are stored in config.inc.php
*
* @param username:String -> Asterisk extension to alert before starting call
* @param password:String -> Password linked to the username
* @param extension:String -> Phonenumber to dial
* @param timeout:int -> Time in which user's phones ring, waiting for response
*
* @return:String -> error message or result of the originate command
*/
function ast_originate($username,$password,$extension,$timeout=0){
	global $db,$API_PROXY_enabled,$API_PROXY_host,$API_PROXY_port;
  if((!is_numeric($timeout))||($timeout<0)) $timeout=0;
  //get data
  $callerid="";
  if(trim($extension)=="") return "ERROR: missing extension to call";
  if((trim($username)!="")||(trim($password)!="")){ 
 		$qry="SELECT c.`technology`, r.`name` as rulename ";
    $qry.="FROM `cw_client` AS c ";
    $qry.="JOIN `cw_rule` AS r ON r.`id`=c.`rule` ";
    $qry.="WHERE c.`extension`='".trim($username)."' ";
    $qry.="AND c.`password`='".trim($password)."' ";
    $qry.="LIMIT 1; ";
    $res=$db->Execute($qry);
    $q=$res->RecordCount();
    if(($q>0)&&($arr=$res->FetchRow())){
      $rule=trim($arr["rulename"]);
      switch($arr["technology"]){
        case SIP:
        		$trunk="SIP/".trim($username);
            $qry="SELECT callerid FROM `sip_buddies` WHERE `name`='".trim($username)."' LIMIT 1; ";
            $res=$db->Execute($qry);
            if(($res!==false)&&($arr=$res->FetchRow())){
            	$callerid=$arr["callerid"];
            }
        	break; 
				case IAX2: 
						$trunk="IAX2/".trim($username);
            $qry="SELECT callerid FROM `iax_buddies` WHERE `name`='".trim($username)."' LIMIT 1; ";
            $res=$db->Execute($qry);
            if(($res!==false)&&($arr=$res->FetchRow())){
            	$callerid=$arr["callerid"];
            }
        	break;
  			case MISDN: 
				case ZAP:
        default:
        	return "ERROR: unsupported user's technologies";
      } 
    }else return "ERROR: login fail";
  }else return "ERROR: invalid username and password";
  //do request
  if($API_PROXY_enabled==0){
  	return "ERROR: Method not implemented via API (only via Proxy)";
  }else{
    //prepare requests
    $actionid="orig".trim($username)."_".rand(100,999);
    $req_login="Action: Login\r\nUsername: ".trim($username)."\r\nSecret: ".trim($password)."\r\n\r\n";
    $req_filter="ProxyAction: SetAutoFilter\r\nAutoFilter: on\r\n\r\n";
    $req_orig="Action: Originate\r\nChannel: ".$trunk."\r\nContext: ".$rule."\r\nExten: ".trim($extension)."\r\nCallerid: ".$callerid."\r\nPriority: 1\r\nTimeout: ".$timeout."\r\nActionID: ".$actionid."\r\n\r\n";
    // ASYNCRONOUS: fputs($socket, "Async: yes\r\n\r\n" );
    $req_logoff="Action: Logoff\r\n\r\n";
    //exec requests
    $sk=@fsockopen($API_PROXY_host,$API_PROXY_port,$errnum,$errstr,60);
    if(!is_resource($sk)) return "ERROR: Unable to connect ".$errnum." ".$errstr;
  	fputs($sk,$req_login); 		// login
    fputs($sk,$req_filter);		// set filter for response
    fputs($sk,$req_orig);			// originate call
    sleep(($timeout/1000)+2); // waiting for originate response before logoff
    fputs($sk,$req_logoff);		// logoff
    //read response
    $response=array();
  	while(!feof($sk)){
  		$row=fgets($sk,2048);
      $response[]=substr($row,0,-1);
  	}
    fclose($sk);
    //parse response
    $orig_response=ast_ParserXML($response,$actionid);
   	//return
    if(trim($orig_response)!="") return $orig_response;
    else return "ERROR: Wrong server response";
  }
}
// ---- Function sendCommand ($cmd:string):int ---------------------------------
/**
* Send a command with the Asterisk API Manager interface
*
* @param cmd:String -> command to execute on asterisk
*
* @return:String -> command's return
*/ 
function sendCommand($cmd) {
  global $floapi,$API_user,$API_pass,$API_host,$API_PROXY_enabled,$API_PROXY_host,$API_PROXY_port;
  //Check if asterisk is ON
  $status=pbxSwitch("status");
  if($status!="ON"){
    error_log("WARNING: pbx off (try to execute command \"$cmd\")");
    return 0;
  }
  //Connect to asterisk via API
  if($API_PROXY_enabled==0){
    $floapi = @new floAPI($API_user, $API_pass, $API_host);
    if($floapi->socket=="") return "ERROR: Unable to connect via API ".$errnum." ".$errstr;
    else{
      //exec request
      $ret=$floapi->request("COMMAND", array("COMMAND" => $cmd));
      $floapi->close();
      if(trim($ret)!="") return $ret;
      else return "ERROR: Wrong server response";
    }
  }
  //Connect to asterisk via PROXY
  else{
  	//prepare requests
    $actionid="cmd".trim($API_user)."_".rand(100,999);
    $req_login="Action: Login\r\nUsername: ".trim($API_user)."\r\nSecret: ".trim($API_pass)."\r\n\r\n";
    $req_filter="ProxyAction: SetAutoFilter\r\nAutoFilter: on\r\n\r\n";
    $req_cmd="Action: Command\r\nCommand: $cmd\r\nActionID: ".$actionid."\r\n\r\n";
    $req_logoff="Action: Logoff\r\n\r\n";
    //exec requests
    $sk=@fsockopen($API_PROXY_host,$API_PROXY_port,$errnum,$errstr,60);
    if(!is_resource($sk)) return "ERROR: Unable to connect via Proxy ".$errnum." ".$errstr;
  	fputs($sk,$req_login); 		// login
    fputs($sk,$req_filter);		// set filter for response
    fputs($sk,$req_cmd);			// exec command
    sleep(1); 								// waiting for command response before logoff
    fputs($sk,$req_logoff);		// logoff
    //read response
    $response=array();
  	while(!feof($sk)){
  		$row=fgets($sk,2048);
      $response[]=substr($row,0,-1);
  	}
    fclose($sk);
    //parse response
    $cmd_response=ast_ParserXML($response,$actionid);
   	//return
    if(trim($cmd_response)!="") return $cmd_response;
    else return "ERROR: Wrong server response";
  }
}

//******************************************************************************
//*****************           PRIVATE FUNCTIONS            *********************
//******************************************************************************
// ---- Function ast_ParserXML -------------------------------------------------
/**
* PRIVATE: parses xml response data and extracts in an array the output of command 
* linked to passed action id 
*
* @param data:Array -> data to parse lines array
* @param actionid:String -> command reference
*
* @return:Array -> array of xml fileds of command's output
*/
function ast_ParserXML($data,$actionid){
	$match=false;
	$block=array();
	if(is_array($data)){
  	foreach($data as $line){
    	if((trim($line)=="")||(substr(trim($line),0,1)!="<")||(substr(trim($line),0,2)=="</")) continue;
			if( ((strlen($line)>=23)&&(substr($line,0,23)=="<AsteriskManagerOutput>")) 			||
      		((strlen($line)>=28)&&(substr($line,0,28)=="<AsteriskManagerProxyOutput>")) ){
      	if($match===true) break;
        else $block=array();            
      }else{
      	$line=substr($line,strpos($line,"<")+1,(strpos($line,"/>")-strpos($line,"<")-1));
       	$lineArr=split(" Value=",$line);
        if((is_array($lineArr))&&(count($lineArr)==2)){
        	//check if block is the response of the request
          if(($lineArr[0]=="ActionID")&&(str_replace("\"","",$lineArr[1])==$actionid)) $match=true;
          //check if line is part of the response's text or it is a response header
          if(trim($lineArr[0])=="UnparsedText"){
          	$block["UnparsedText"][]=str_replace("\"","",$lineArr[1]);
         	}else{
          	$block[$lineArr[0]]=str_replace("\"","",$lineArr[1]);
          }
        }     
			}
  	}
  }
  //return
  $ret="";
  if(($match===true)&&(is_array($block))){
  	foreach($block as $k=>$v){
    	if(($k=="ActionID")||($k=="Server")) continue;
    	if(is_array($v)) $ret.=implode("\n",$v);
      else $ret.=$k.": ".$v."\n";
    }
  }
  return $ret;
}
// ---- Function ast_writeProxyUsers -------------------------------------------
/**
* PRIVATE: write astmanproxy.users file with one entry per clients
*
* @param void
*
* @return:int -> Always 1, not able to recognize errors
*/
function ast_writeProxyUsers(){
	global $db,$API_user,$API_pass,$API_PROXY_users,$voTools;
  //delete users file
  exec("sudo $voTools delAstProxyUsers $API_PROXY_users",$output,$retScript);
  //add system access
  exec("sudo $voTools addAstProxyUser $API_PROXY_users $API_user $API_pass",$output,$retScript);
  //extract users
  $qry="SELECT `extension`,`password`,`technology` ";
  $qry.="FROM `cw_client` ";
  $qry.="WHERE `technology`='".SIP."' ";
  $qry.="OR `technology`='".IAX2."' ";
  $res=$db->Execute($qry);
  while($arr=$res->FetchRow()){
  	$extension=$arr["extension"];
    $password=$arr["password"];
    if($arr["technology"]==SIP) $channel="SIP/".$arr["extension"]; 
    else $channel="IAX2/".$arr["extension"];;
  	exec("sudo $voTools addAstProxyUser $API_PROXY_users $extension $password $channel",$output,$retScript);
  }
  return 1;
}

?>